/*
MBA PDB TPI Parser Implementation.

This file is part of MBA PDB Parser.
This PDB parser is modified from RADARE2's repository.
Instead of using radare's API, we replace it with ut-serial library.

Copyright (c)   2016 ChongKuan Chen

This PDB Parser is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Foobar is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "types.h"
#include "tpi.h"
#include "stream_file.h"

#include "utarray.h"

static unsigned int base_idx = 0;
static UT_array *p_types_list;

void print_base_type(EBASE_TYPES base_type, char **name)
{
	switch (base_type) {
	case eT_32PINT4:
		*name = "long*";
		break;
	case eT_32PRCHAR:
		*name = "unsigned char*";
		break;
	case eT_32PUCHAR:
		*name = "unsigned char*";
		break;
	case eT_32PULONG:
		*name = "unsigned long*";
		break;
	case eT_32PLONG:
		*name = "long*";
		break;
	case eT_32PUQUAD:
		*name = "unsigned long long*";
		break;
	case eT_32PUSHORT:
		*name = "unsigned short*";
		break;
	case eT_32PVOID:
		*name = "void*";
		break;
	case eT_64PVOID:
		*name = "void*";
		break;
	case eT_INT4:
		*name = "long";
		break;
	case eT_INT8:
		*name = "long long";
		break;
	case eT_LONG:
		*name = "long";
		break;
	case eT_QUAD:
		*name = "long long";
		break;
	case eT_RCHAR:
		*name = "unsigned char";
		break;
	case eT_REAL32:
		*name = "float";
		break;
	case eT_REAL64:
		*name = "double";
		break;
	case eT_REAL80:
		*name = "long double";
		break;
	case eT_SHORT:
		*name = "short";
		break;
	case eT_UCHAR:
		*name = "unsigned char";
		break;
	case eT_UINT4:
		*name = "unsigned long";
		break;
	case eT_ULONG:
		*name = "unsigned long";
		break;
	case eT_UQUAD:
		*name = "unsigned long long";
		break;
	case eT_USHORT:
		*name = "unsigned short";
		break;
	case eT_WCHAR:
		*name = "wchar";
		break;
	case eT_VOID:
		*name = "void";
		break;
	case eT_32PWCHAR:
		*name = "wchar*";
		break;
	default:
		*name = "unsupported base type";
		break;
	}
}

void free_sval(SVal *val)
{
	if (val->value_or_type < eLF_CHAR) {
		SCString *scstr;
		scstr = (SCString *) val->name_or_val;
		free(scstr->name);
		free(val->name_or_val);
	} else {
		switch (val->value_or_type) {
		case eLF_ULONG:
		{
			SVal_LF_ULONG *lf_ulong;
			lf_ulong = (SVal_LF_ULONG *) val->name_or_val;
			free(lf_ulong->name.name);
			free(val->name_or_val);
			break;
		}
		case eLF_LONG:
		{
			SVal_LF_LONG *lf_long;
			lf_long = (SVal_LF_LONG *) val->name_or_val;
			free(lf_long->name.name);
			free(val->name_or_val);
			break;
		}
		case eLF_SHORT:
		{
			SVal_LF_SHORT *lf_short;
			lf_short = (SVal_LF_SHORT *) val->name_or_val;
			free(lf_short->name.name);
			free(val->name_or_val);
			break;
		}
		case eLF_USHORT:
		{
			SVal_LF_USHORT *lf_ushort;
			lf_ushort = (SVal_LF_USHORT *) val->name_or_val;
			free(lf_ushort->name.name);
			free(val->name_or_val);
			break;
		}
		case eLF_CHAR:
		{
			SVal_LF_CHAR *lf_char;
			lf_char = (SVal_LF_CHAR *) val->name_or_val;
			free(lf_char->name.name);
			free(val->name_or_val);
			break;
		}
		default:
			printf("free_sval()::not supproted type\n");
			break;
		}
	}
}


// eLF_FIELDLIST
void get_fieldlist_members(void *type, void **l)
{
	STypeInfo *t = (STypeInfo *) type;
	SLF_FIELDLIST *lf_fieldlist = (SLF_FIELDLIST *) t->type_info;

	*l = lf_fieldlist->substructs;
}


//TODO: Need to tesing
void free_lf_fieldlist(void *type)
{
	STypeInfo *t = (STypeInfo *) type;
	SLF_FIELDLIST *lf_fieldlist = (SLF_FIELDLIST *) t->type_info;
	//RListIter *it;
        STypeInfo *it;
        //SLF_FIELDLIST_SUBSTRUCT *it, *tmp;
	STypeInfo *type_info = 0;

        it=NULL;
        while( (it=(STypeInfo*)utarray_next(lf_fieldlist->substructs, it))) {
                type_info = it;
                if (type_info->free_)
                        type_info->free_(type_info);
                if (type_info->type_info) {
                        free(type_info->type_info);
                }
                free(type_info);      
        }
	//r_list_free(lf_fieldlist->substructs);
        /*DL_FOREACH_SAFE(lf_fieldlist->substructs, it, tmp)
        {
                DL_DELETE(lf_fieldlist->substructs,it);
                free(it);
        } */ 
        free(lf_fieldlist->substructs);
}

void get_fieldlist_print_type(void *type, char **name, int* pcount)
{
	int name_len = 0;

	name_len = strlen("fieldlist ");
	*name = (char *) malloc(name_len + 1);
	// name[name_len] = '\0';
	strcpy(*name, "fieldlist ");
}

// eLF_ENUM
void get_enum_name(void *type, char **name)
{
	STypeInfo *t = (STypeInfo *) type;
	SLF_ENUM *lf_enum = (SLF_ENUM *)t->type_info;

	*name = lf_enum->name.name;
}

void get_enum_name_len(void *type, int *res_len)
{
	STypeInfo *t = (STypeInfo *) type;
	SLF_ENUM *lf_enum = (SLF_ENUM *)t->type_info;

	*res_len = lf_enum->name.size;
}

void get_enum_members(void *type, void **list)
{
        UT_array **l = (UT_array **)list;
	STypeInfo *t = (STypeInfo *) type;
	SLF_ENUM *lf = (SLF_ENUM *) t->type_info;
	unsigned int indx = 0;

	if (lf->field_list == 0) {
		*l = 0;
	} else {
		SType *tmp = 0;
		indx = lf->field_list - base_idx;
		//tmp = (SType *)r_list_get_n(p_types_list, indx);
                tmp = (SType *)utarray_eltptr(p_types_list, indx);
		*l = ((SLF_FIELDLIST *)(tmp->type_data.type_info))->substructs;

	}
}

int get_enum_utype(void *type, void **ret_type)
{
	STypeInfo *t = (STypeInfo *) type;
	SLF_ENUM *lf = (SLF_ENUM *) t->type_info;
	int curr_idx = lf->utype;

	if (curr_idx < base_idx) {
		*ret_type = 0;
	} else {
		curr_idx -= base_idx;
		//*ret_type = r_list_get_n(p_types_list, curr_idx);
                *ret_type = (SType *)utarray_eltptr(p_types_list, curr_idx);
	}

	return curr_idx;
}

void free_lf_enum(void *type)
{
	STypeInfo *t = (STypeInfo *) type;
	SLF_ENUM *lf_enum = (SLF_ENUM *) t->type_info;

	free(lf_enum->name.name);
}

void get_enum_print_type(void *type, char **name, int* pcount)
{
	STypeInfo *ti = (STypeInfo *) type;
	SType *t = 0;
	char *tmp_name = 0;
	int name_len = 0;
	int need_to_free = 1;
	int base_type = 0;

	base_type = ti->get_utype(ti, (void **)&t);
	if (!t) {
		need_to_free = 0;
		print_base_type(base_type, &tmp_name);
	} else {
		ti = &t->type_data;
		ti->get_print_type(ti, &tmp_name, pcount);
	}

	name_len = strlen("enum ");
	if (tmp_name)
		name_len += strlen(tmp_name);
	*name = (char *) malloc(name_len + 1);
	// name[name_len] = '\0';
	strcpy(*name, "enum ");
	if (tmp_name)
		strcat(*name, tmp_name);

	if (need_to_free)
		free(tmp_name);
}

//eLF_STRUCTURE
void get_sval_name_len(SVal *val, int *res_len)
{
	if (val->value_or_type < eLF_CHAR) {
		SCString *scstr;
		scstr = (SCString *) val->name_or_val;
		*res_len = scstr->size;
	} else {
		switch (val->value_or_type) {
		case eLF_ULONG:
		{
			SVal_LF_ULONG *lf_ulong;
			lf_ulong = (SVal_LF_ULONG *) val->name_or_val;
			*res_len = lf_ulong->name.size;
			break;
		}
		case eLF_USHORT:
		{
			SVal_LF_USHORT *lf_ushort;
			lf_ushort = (SVal_LF_USHORT *) val->name_or_val;
			*res_len = lf_ushort->name.size;
			break;
		}
		default:
			*res_len = 0;
			printf("get_sval_name::oops\n");
			break;
		}
	}
}

void get_sval_val(SVal *val, int *res)
{
	if (val->value_or_type < eLF_CHAR) {
		*res = val->value_or_type;
	} else {
		switch (val->value_or_type) {
		case eLF_ULONG:
		{
			SVal_LF_ULONG *lf_ulong;
			lf_ulong = (SVal_LF_ULONG *) val->name_or_val;
			*res = lf_ulong->value;
			break;
		}
		case eLF_LONG:
		{
			SVal_LF_LONG *lf_long;
			lf_long = (SVal_LF_LONG *) val->name_or_val;
			*res = lf_long->value;
			break;
		}
		case eLF_USHORT:
		{
			SVal_LF_USHORT *lf_ushort;
			lf_ushort = (SVal_LF_USHORT *) val->name_or_val;
			*res = lf_ushort->value;
			break;
		}
		case eLF_CHAR:
		{
			SVal_LF_CHAR *lf_char;
			lf_char = (SVal_LF_CHAR *) val->name_or_val;
			*res = lf_char->value;
			break;
		}

		default:
			*res = 0;
			printf("get_sval_val::oops\n");
			break;
		}
	}
}

void get_sval_name(SVal *val, char **name)
{
	if (val->value_or_type < eLF_CHAR) {
		SCString *scstr;
		scstr = (SCString *) val->name_or_val;
		*name = scstr->name;
//		strcpy(name, scstr->name);
	} else {
		switch (val->value_or_type) {
		case eLF_CHAR:
		{
			SVal_LF_CHAR *lf_char;
			lf_char = (SVal_LF_CHAR *) val->name_or_val;
			*name = lf_char->name.name;
//			strcpy(name, lf_uchar->name.name);
			break;
		}
		case eLF_ULONG:
		{
			SVal_LF_ULONG *lf_ulong;
			lf_ulong = (SVal_LF_ULONG *) val->name_or_val;
			*name = lf_ulong->name.name;
//			strcpy(name, lf_ulong->name.name);
			break;
		}
		case eLF_LONG:
		{
			SVal_LF_LONG *lf_long;
			lf_long = (SVal_LF_LONG *) val->name_or_val;
			*name = lf_long->name.name;
//			strcpy(name, lf_long->name.name);
			break;
		}
		case eLF_USHORT:
		{
			SVal_LF_USHORT *lf_ushort;
			lf_ushort = (SVal_LF_USHORT *) val->name_or_val;
			*name =lf_ushort->name.name;
//			strcpy(name, lf_ushort->name.name);
			break;
		}
		default:
			*name = 0;
			printf("get_sval_name::oops\n");
			break;
		}
	}
}

void get_class_struct_name_len(void *type, int *res_len)
{
	STypeInfo *t = (STypeInfo *) type;
	SLF_STRUCTURE *lf = (SLF_STRUCTURE *)t->type_info;

	get_sval_name_len(&lf->size, res_len);
}

void get_class_struct_val(void *type, int *res)
{
	STypeInfo *t = (STypeInfo *) type;
	SLF_STRUCTURE *lf = (SLF_STRUCTURE *) t->type_info;

	get_sval_val(&lf->size, res);
}

void get_class_struct_name(void *type, char **name)
{
	STypeInfo *t = (STypeInfo *) type;
	SLF_STRUCTURE *lf = (SLF_STRUCTURE *)t->type_info;

	get_sval_name(&lf->size, name);
}

void get_struct_class_members(void *type, void **list)
{
        UT_array **l = (UT_array **)list;
	SLF_FIELDLIST *lf_fieldlist = 0;
	STypeInfo *t = (STypeInfo *) type;
	SLF_STRUCTURE *lf = (SLF_STRUCTURE *) t->type_info;
	unsigned int indx = 0;

	if (lf->field_list == 0) {
		*l = 0;
	} else {
		SType *tmp = 0;
		indx = lf->field_list - base_idx;
                tmp = (SType *)utarray_eltptr(p_types_list, indx);
		lf_fieldlist = (SLF_FIELDLIST *) tmp->type_data.type_info;
		*l = lf_fieldlist->substructs;
	}
}

int get_class_struct_derived(void *type, void **ret_type)
{
	STypeInfo *t = (STypeInfo *) type;
	SLF_STRUCTURE *lf = (SLF_STRUCTURE *) t->type_info;
	int curr_idx = lf->derived;

	if (curr_idx < base_idx) {
		*ret_type = 0;
	} else {
		curr_idx -= base_idx;
                *ret_type = (SType *)utarray_eltptr(p_types_list, curr_idx);
	}

	return curr_idx;
}

int get_class_struct_vshape(void *type, void **ret_type)
{
	STypeInfo *t = (STypeInfo *) type;
	SLF_STRUCTURE *lf = (SLF_STRUCTURE *) t->type_info;
	int curr_idx = lf->vshape;

	if (curr_idx < base_idx) {
		*ret_type = 0;
	} else {
		curr_idx -= base_idx;
                *ret_type = (SType *)utarray_eltptr(p_types_list, curr_idx);
	}

	return curr_idx;
}

void is_struct_class_fwdref(void *type, int *is_fwdref)
{
	STypeInfo *t = (STypeInfo *) type;
	SLF_STRUCTURE *lf = (SLF_STRUCTURE *) t->type_info;

	*is_fwdref = lf->prop.bits.fwdref;
}

void free_lf_class(void *type)
{
	STypeInfo *t = (STypeInfo *) type;
	SLF_CLASS *lf_class = (SLF_CLASS *) t->type_info;

	free_sval(&lf_class->size);
}

void get_class_struct_print_type(void *type, char **name, int* pcount)
{
	STypeInfo *ti = (STypeInfo *) type;
	ELeafType lt;
	char *tmp_name = 0, *tmp1 = 0;
	int name_len = 0;

	lt = ti->leaf_type;
	ti->get_name(ti, &tmp_name);
        //ti->get_name(ti, name);

        /*
	if (lt == eLF_CLASS) {
		tmp1 = "class ";
	} else {
		tmp1 = "struct ";
	}
	name_len = strlen(tmp1);
        */
	if (tmp_name)
		name_len += strlen(tmp_name);
	*name = (char *) malloc(name_len + 1);
	// name[name_len] = '\0';
	//strcpy(*name, tmp1);
	if (tmp_name)
		strcpy(*name, tmp_name);
        
//	if (need_to_free) {
//		free(tmp_name);
//		tmp_name = 0;
//	}
}

// eLF_POINTER
int get_pointer_utype(void *type, void **ret_type)
{
	STypeInfo *t = (STypeInfo *) type;
	SLF_POINTER *lf = (SLF_POINTER *) t->type_info;
	int curr_idx = lf->utype;

	if (curr_idx < base_idx) {
		*ret_type = 0;
	} else {
		curr_idx -= base_idx;
                *ret_type = (SType *)utarray_eltptr(p_types_list, curr_idx);
	}

	return curr_idx;
}

void get_pointer_print_type(void *type, char **name, int* pcount )
{
	STypeInfo *ti = (STypeInfo *) type;
	SType *t = 0;
	char *tmp_name = 0;
	int name_len = 0;
	int need_to_free = 1;
	int base_type = 0;

        *pcount = *pcount+1;

	base_type = ti->get_utype(ti, (void **)&t);
	if (!t) {
		need_to_free = 0;
		print_base_type(base_type, &tmp_name);
	} else {
		ti = &t->type_data;
		ti->get_print_type(ti, &tmp_name, pcount);
	}

	//name_len = strlen("*");
	if (tmp_name)
		name_len += strlen(tmp_name);
	*name = (char *) malloc(name_len + 1);
	// name[name_len] = '\0';
        strcpy(*name, "");
        if (tmp_name)
                strcat(*name, tmp_name);
	//strcpy(*name, "*");
	//if (tmp_name)
	//	strcat(*name, tmp_name);
        //strcat(*name, "*");

	if (need_to_free) {
		free(tmp_name);
		tmp_name = 0;
	}
}

// eLF_ARRAY
void get_array_name_len(void *type, int *res_len)
{
	STypeInfo *t = (STypeInfo *) type;
	SLF_ARRAY *lf_array = (SLF_ARRAY *) t->type_info;

	get_sval_name_len(&lf_array->size, res_len);
}

void get_array_name(void *type, char **name)
{
	STypeInfo *t = (STypeInfo *) type;
	SLF_ARRAY *lf_array = (SLF_ARRAY *) t->type_info;

	get_sval_name(&lf_array->size, name);
}

void get_array_val(void *type, int *res)
{
	STypeInfo *t = (STypeInfo *) type;
	SLF_ARRAY *lf_array = (SLF_ARRAY *) t->type_info;

	get_sval_val(&lf_array->size, res);
}

int get_array_element_type(void *type, void **ret_type)
{
	STypeInfo *t = (STypeInfo *) type;
	SLF_ARRAY *lf_array = (SLF_ARRAY *) t->type_info;
	int curr_idx = lf_array->element_type;

	if (curr_idx < base_idx) {
		*ret_type = 0;
	} else {
		curr_idx -= base_idx;
		//*ret_type = r_list_get_n(p_types_list, curr_idx);
                *ret_type = (SType *)utarray_eltptr(p_types_list, curr_idx);
	}

	return curr_idx;
}

int get_array_index_type(void *type, void **ret_type)
{
	STypeInfo *t = (STypeInfo *) type;
	SLF_ARRAY *lf_array = (SLF_ARRAY *) t->type_info;
	int curr_idx = lf_array->index_type;

	if (curr_idx < base_idx) {
		*ret_type = 0;
	} else {
		curr_idx -= base_idx;
		//*ret_type = r_list_get_n(p_types_list, curr_idx);
                *ret_type = (SType *)utarray_eltptr(p_types_list, curr_idx);
	}

	return curr_idx;
}

void free_lf_array(void *type)
{
	STypeInfo *t = (STypeInfo *) type;
	SLF_ARRAY *lf_array = (SLF_ARRAY *) t->type_info;

	free_sval(&lf_array->size);
}

void get_array_print_type(void *type, char **name, int* pcount)
{
	STypeInfo *ti = (STypeInfo *) type;
	SType *t = 0;
	char *tmp_name = 0;
	int name_len = 0;
	int need_to_free = 1;
	int base_type = 0;

	base_type = ti->get_element_type(ti, (void **)&t);
	if (!t) {
		need_to_free = 0;
		print_base_type(base_type, &tmp_name);
	} else {
		ti = &t->type_data;
		ti->get_print_type(ti, &tmp_name, pcount);
	}

	name_len = strlen("array: ");
	if (tmp_name)
		name_len += strlen(tmp_name);
	*name = (char *) malloc(name_len + 1);
	// name[name_len] = '\0';
	strcpy(*name, "array: ");
	if (tmp_name)
		strcat(*name, tmp_name);

	if (need_to_free) {
		free(tmp_name);
		tmp_name = 0;
	}
}

// eLF_MODIFIER

int get_modifier_modified_type(void *type, void **ret_type)
{
	STypeInfo *t = (STypeInfo *) type;
	SLF_MODIFIER *lf = (SLF_MODIFIER *) t->type_info;
	int curr_idx = lf->modified_type;

	if (curr_idx < base_idx) {
		*ret_type = 0;
	} else {
		curr_idx -= base_idx;
		//*ret_type = r_list_get_n(p_types_list, curr_idx);
                 *ret_type = (SType *)utarray_eltptr(p_types_list, curr_idx);
	}

	return curr_idx;
}

void get_modifier_print_type(void *type, char **name, int* pcount)
{
	STypeInfo *ti = (STypeInfo *) type;
	SType *t = 0;
	char *tmp_name = 0;
	int name_len = 0;
	int need_to_free = 1;
	int base_type = 0;

	base_type = ti->get_modified_type(ti, (void **)&t);
	if (!t) {
		need_to_free = 0;
		print_base_type(base_type, &tmp_name);
	} else {
		ti = &t->type_data;
		ti->get_print_type(ti, &tmp_name, pcount);
	}

	name_len = strlen("modifier ");
	if (tmp_name)
		name_len += strlen(tmp_name);
	*name = (char *) malloc(name_len + 1);
	// name[name_len] = '\0';
	strcpy(*name, "modifier ");
	if (tmp_name)
		strcat(*name, tmp_name);

	if (need_to_free) {
		free(tmp_name);
		tmp_name = 0;
	}
}

// eLF_ARGLIST

void free_lf_arglist(void *type)
{
	STypeInfo *t = (STypeInfo *) type;
	SLF_ARGLIST *lf_arglist = (SLF_ARGLIST *) t->type_info;

	free(lf_arglist->arg_type);
	lf_arglist->arg_type = 0;
}

void get_arglist_print_type(void *type, char **name, int* pcount)
{
	(void) type;
	int name_len = 0;

	name_len = strlen("arg_list");
	*name = (char *) malloc(name_len + 1);
	// name[name_len] = '\0';
	strcpy(*name, "arg_list");
//	STypeInfo *ti = (STypeInfo *) type;
//	SType *t = 0;
//	char *tmp_name = 0;
//	int name_len = 0;
//	int need_to_free = 1;
//	int base_type = 0;

//	base_type = ti->get_arg_type(ti, (void **)&t);
//	if (!t) {
//		need_to_free = 0;
//		print_base_type(base_type, &tmp_name);
//	} else {
//		ti = &t->type_data;
//		ti->get_print_type(ti, &tmp_name);
//	}

//	name_len = strlen("arglist ");
//	name_len += strlen(tmp_name);
//	*name = (char *) malloc(name_len + 1);
//	// name[name_len] = '\0';
//	strcpy(*name, "arglist ");
//	strcat(*name, tmp_name);

//	if (need_to_free)
//		free(tmp_name);
}

// eLF_MFUNCTION

int get_mfunction_return_type(void *type, void **ret_type)
{
	STypeInfo *t = (STypeInfo *) type;
	SLF_MFUNCTION *lf = (SLF_MFUNCTION *) t->type_info;
	int curr_idx = lf->return_type;

	if (curr_idx < base_idx) {
		*ret_type = 0;
	} else {
		curr_idx -= base_idx;
		//*ret_type = r_list_get_n(p_types_list, curr_idx);
                *ret_type = (SType *)utarray_eltptr(p_types_list, curr_idx);
	}

	return curr_idx;
}

int get_mfunction_class_type(void *type, void **ret_type)
{
	STypeInfo *t = (STypeInfo *) type;
	SLF_MFUNCTION *lf = (SLF_MFUNCTION *) t->type_info;
	int curr_idx = lf->class_type;

	if (curr_idx < base_idx) {
		*ret_type = 0;
	} else {
		curr_idx -= base_idx;
		//*ret_type = r_list_get_n(p_types_list, curr_idx);
                 *ret_type = (SType *)utarray_eltptr(p_types_list, curr_idx);
	}

	return curr_idx;
}

int get_mfunction_this_type(void *type, void **ret_type)
{
	STypeInfo *t = (STypeInfo *) type;
	SLF_MFUNCTION *lf = (SLF_MFUNCTION *) t->type_info;
	int curr_idx = lf->this_type;

	if (curr_idx < base_idx) {
		*ret_type = 0;
	} else {
		curr_idx -= base_idx;
		//*ret_type = r_list_get_n(p_types_list, curr_idx);
                *ret_type = (SType *)utarray_eltptr(p_types_list, curr_idx);
	}

	return curr_idx;
}

int get_mfunction_arglist(void *type, void **ret_type)
{
	STypeInfo *t = (STypeInfo *) type;
	SLF_MFUNCTION *lf = (SLF_MFUNCTION *) t->type_info;
	int curr_idx = lf->arglist;

	if (curr_idx < base_idx) {
		*ret_type = 0;
	} else {
		curr_idx -= base_idx;
		//*ret_type = r_list_get_n(p_types_list, curr_idx);
                 *ret_type = (SType *)utarray_eltptr(p_types_list, curr_idx);
	}

	return curr_idx;
}

void get_mfunction_print_type(void *type, char **name, int* pcount)
{
	int name_len = 0;

	name_len = strlen("mfunction ");
	*name = (char *) malloc(name_len + 1);
	// name[name_len] = '\0';
	strcpy(*name, "mfunction ");
}

// eLF_PROCEDURE

int get_procedure_return_type(void *type, void **ret_type)
{
	STypeInfo *t = (STypeInfo *) type;
	SLF_PROCEDURE *lf = (SLF_PROCEDURE *) t->type_info;
	int curr_idx = lf->return_type;

	if (curr_idx < base_idx) {
		*ret_type = 0;
	} else {
		curr_idx -= base_idx;
		//*ret_type = r_list_get_n(p_types_list, curr_idx);
                *ret_type = (SType *)utarray_eltptr(p_types_list, curr_idx);
	}

	return curr_idx;
}

int get_procedure_arglist(void *type, void **ret_type)
{
	STypeInfo *t = (STypeInfo *) type;
	SLF_PROCEDURE *lf = (SLF_PROCEDURE *) t->type_info;
	int curr_idx = lf->arg_list;

	if (curr_idx < base_idx) {
		*ret_type = 0;
	} else {
		curr_idx -= base_idx;
		//*ret_type = r_list_get_n(p_types_list, curr_idx);
                *ret_type = (SType *)utarray_eltptr(p_types_list, curr_idx);
	}

	return curr_idx;
}

void get_procedure_print_type(void *type, char **name, int *pcount)
{
	int name_len = 0;

	name_len = strlen("proc ");
	*name = (char *) malloc(name_len + 1);
	// name[name_len] = '\0';
	strcpy(*name, "proc ");
}

// eLF_UNION

void get_union_name_len(void *type, int *res_len)
{
	STypeInfo *t = (STypeInfo *) type;
	SLF_UNION *lf_union = (SLF_UNION *) t->type_info;

	get_sval_name_len(&lf_union->size, res_len);
}

void get_union_name(void *type, char **name)
{
	STypeInfo *t = (STypeInfo *) type;
	SLF_UNION *lf_union = (SLF_UNION *) t->type_info;

	get_sval_name(&lf_union->size, name);
}

void get_union_val(void *type, int *res)
{
	STypeInfo *t = (STypeInfo *) type;
	SLF_UNION *lf_union = (SLF_UNION *) t->type_info;

	get_sval_val(&lf_union->size, res);
}

void get_union_members(void *type, void **list)
{
        UT_array **l = (UT_array **)list;
	STypeInfo *t = (STypeInfo *) type;
	SLF_UNION *lf_union = (SLF_UNION *) t->type_info;
	unsigned int indx = 0;

	if (lf_union->field_list == 0) {
		*l = 0;
	} else {
		SType *tmp = 0;
		indx = lf_union->field_list - base_idx;
		//tmp = (SType *)r_list_get_n(p_types_list, indx);
                tmp = (SType *)utarray_eltptr(p_types_list, indx);
		*l = ((SLF_FIELDLIST *) tmp->type_data.type_info)->substructs;
	}
}

void is_union_fwdref(void *type, int *is_fwdref)
{
	STypeInfo *t = (STypeInfo *) type;
	SLF_UNION *lf = (SLF_UNION *) t->type_info;

	*is_fwdref = lf->prop.bits.fwdref;
}

void free_lf_union(void *type)
{
	STypeInfo *t = (STypeInfo *) type;
	SLF_UNION *lf_union = (SLF_UNION *) t->type_info;

	free_sval(&lf_union->size);
}

void get_union_print_type(void *type, char **name, int* pcount)
{
	STypeInfo *ti = (STypeInfo *) type;
//	ELeafType lt;
	char *tmp_name = 0, *tmp1 = 0;
	int name_len = 0;

//	lt = ti->leaf_type;
	ti->get_name(ti, &tmp_name);

	tmp1 = "union ";
	name_len = strlen(tmp1);
	if (tmp_name)
		name_len += strlen(tmp_name);
	*name = (char *) malloc(name_len + 1);
	// name[name_len] = '\0';
	strcpy(*name, tmp1);
	if (tmp_name)
		strcat(*name, tmp_name);

//	if (need_to_free) {
//		free(tmp_name);
//		tmp_name = 0;
//	}
}

// eLF_BITFIELD

int get_bitfield_base_type(void *type, void **ret_type)
{
	STypeInfo *t = (STypeInfo *) type;
	SLF_BITFIELD *lf = (SLF_BITFIELD *) t->type_info;
	int curr_idx = lf->base_type;

	if (curr_idx < base_idx) {
		*ret_type = 0;
	} else {
		curr_idx -= base_idx;
		//*ret_type = r_list_get_n(p_types_list, curr_idx);
                *ret_type = (SType *)utarray_eltptr(p_types_list, curr_idx);
	}

	return curr_idx;
}

void get_bitfield_print_type(void *type, char **name, int* pcount)
{
	STypeInfo *ti = (STypeInfo *) type;
	SType *t = 0;
	char *tmp_name = 0;
	int name_len = 0;
	int need_to_free = 1;
	int base_type = 0;
	SLF_BITFIELD *bitfeild_info = (SLF_BITFIELD *)ti->type_info;

	base_type = ti->get_base_type(ti, (void **)&t);
	if (!t) {
		need_to_free = 0;
		print_base_type(base_type, &tmp_name);
	} else {
		ti = &t->type_data;
		ti->get_print_type(ti, &tmp_name, pcount);
	}

	name_len = strlen("bitfield ");
	if (tmp_name)
		name_len += strlen(tmp_name);
	name_len += 4;
	*name = (char *) malloc(name_len + 1 + 1);
	// name[name_len] = '\0';
	if (tmp_name) {
		sprintf(*name, "%s %s : %d", "bitfield", tmp_name, (int)bitfeild_info->length);
	} else {
		sprintf(*name, "%s : %d", "bitfield", (int)bitfeild_info->length);
	}

	if (need_to_free)
		free(tmp_name);
}

// eLF_VTSHAPE

void free_lf_vtshape(void *type)
{
	STypeInfo *t = (STypeInfo *) type;
	SLF_VTSHAPE *lf_vtshape = (SLF_VTSHAPE *) t->type_info;

	free(lf_vtshape->vt_descriptors);
	lf_vtshape->vt_descriptors = 0;
}

void get_vtshape_print_type(void *type, char **name, int* pcount)
{
	int name_len = 0;

	name_len = strlen("vtshape");
	*name = (char *) malloc(name_len + 1);
	// name[name_len] = '\0';
	strcpy(*name, "vthape");
}

// eLF_ENUMERATE

void get_enumerate_name_len(void *type, int *res_len)
{
	STypeInfo *t = (STypeInfo *) type;
	SLF_ENUMERATE *lf = (SLF_ENUMERATE *)t->type_info;

	get_sval_name_len(&lf->enum_value, res_len);
}

void get_enumerate_name(void *type, char **name)
{
	STypeInfo *t = (STypeInfo *) type;
	SLF_ENUMERATE *lf = (SLF_ENUMERATE *)t->type_info;

	get_sval_name(&lf->enum_value, name);
}

void get_enumerate_val(void *type, int *res)
{
	STypeInfo *t = (STypeInfo *) type;
	SLF_ENUMERATE *lf = (SLF_ENUMERATE *)t->type_info;

	get_sval_val(&lf->enum_value, res);
}

void free_lf_enumerate(void *type_info)
{
	STypeInfo *typeInfo = (STypeInfo *) type_info;
	SLF_ENUMERATE *lf_en = (SLF_ENUMERATE *) typeInfo->type_info;

	free_sval(&(lf_en->enum_value));
}

void get_enumerate_print_type(void *type, char **name, int* pcount)
{
	STypeInfo *ti = (STypeInfo *) type;
	char *tmp_name = 0, *tmp1 = 0;
	int name_len = 0;

	ti->get_name(ti, &tmp_name);

	tmp1 = "enumerate ";
	name_len = strlen(tmp1);
	if (tmp_name)
		name_len += strlen(tmp_name);
	*name = (char *) malloc(name_len + 1);
	// name[name_len] = '\0';
	strcpy(*name, tmp1);
	if (tmp_name)
	strcat(*name, tmp_name);

//	if (need_to_free)
//		free(tmp_name);
}

// eLF_NESTTYPE

void get_nesttype_name_len(void *type, int *res)
{
	STypeInfo *t = (STypeInfo *) type;
	SLF_NESTTYPE *lf = (SLF_NESTTYPE *)t->type_info;

	*res = lf->name.size;
}

void get_nesttype_name(void *type, char **name)
{
	STypeInfo *t = (STypeInfo *) type;
	SLF_NESTTYPE *lf = (SLF_NESTTYPE *)t->type_info;

	*name = lf->name.name;
}

int get_nesttype_index(void *type, void **ret_type)
{
	STypeInfo *t = (STypeInfo *) type;
	SLF_NESTTYPE *lf = (SLF_NESTTYPE *) t->type_info;
	int curr_idx = lf->index;

	if (curr_idx < base_idx) {
		*ret_type = 0;
	} else {
		curr_idx -= base_idx;
		//*ret_type = r_list_get_n(p_types_list, curr_idx);
                *ret_type = (SType *)utarray_eltptr(p_types_list, curr_idx);
	}

	return curr_idx;
}

void free_lf_nesttype(void *type_info)
{
	STypeInfo *typeInfo = (STypeInfo *) type_info;
	SLF_NESTTYPE *lf_nest = (SLF_NESTTYPE *) typeInfo->type_info;

	free(lf_nest->name.name);
}

void get_nesttype_print_type(void *type, char **name, int * pcount)
{
	STypeInfo *ti = (STypeInfo *) type;
	SType *t = 0;
	char *tmp_name = 0;
	int name_len = 0;
	int need_to_free = 1;
	int base_type = 0;

	base_type = ti->get_index(ti, (void **)&t);
	if (!t) {
		need_to_free = 0;
		print_base_type(base_type, &tmp_name);
	} else {
		ti = &t->type_data;
		if (ti->get_print_type != NULL) {
			ti->get_print_type(ti, &tmp_name, pcount);
		} else {
			// TODO: need to investigate why this branch can be...
			//	this is possible because there is no support for
			// parsing METHODLIST...
			// need to investigate for this theme
			printf("warning: strange for nesttype\n");
		}
	}

	name_len = strlen("nesttype ");
	if (tmp_name)
		name_len += strlen(tmp_name);
	*name = (char *) malloc(name_len + 1);
	// name[name_len] = '\0';
	strcpy(*name, "nesttype ");
	if (tmp_name)
		strcat(*name, tmp_name);

	if (need_to_free)
		free(tmp_name);
}

// eLF_METHOD

void get_method_name_len(void *type, int *res)
{
	STypeInfo *t = (STypeInfo *) type;
	SLF_METHOD *lf = (SLF_METHOD *)t->type_info;

	*res = lf->name.size;
}

void get_method_name(void *type, char **name)
{
	STypeInfo *t = (STypeInfo *) type;
	SLF_METHOD *lf = (SLF_METHOD *)t->type_info;

	*name = lf->name.name;
}

int get_method_mlist(void *type, void **ret_type)
{
	STypeInfo *t = (STypeInfo *) type;
	SLF_METHOD *lf = (SLF_METHOD *) t->type_info;
	int curr_idx = lf->mlist;

	if (curr_idx < base_idx) {
		*ret_type = 0;
	} else {
		curr_idx -= base_idx;
		//*ret_type = r_list_get_n(p_types_list, curr_idx);
                *ret_type = (SType *)utarray_eltptr(p_types_list, curr_idx);
	}

	return curr_idx;
}

void free_lf_method(void *type_info)
{
	STypeInfo *typeInfo = (STypeInfo *) type_info;
	SLF_METHOD *lf_meth = (SLF_METHOD *) typeInfo->type_info;

	free(lf_meth->name.name);
}

void get_method_print_type(void *type, char **name, int* pcount)
{
	STypeInfo *ti = (STypeInfo *) type;
	char *tmp_name = 0, *tmp1 = 0;
	int name_len = 0;

	ti->get_name(ti, &tmp_name);

	tmp1 = "method ";
	name_len = strlen(tmp1);
	if (tmp_name)
		name_len += strlen(tmp_name);
	*name = (char *) malloc(name_len + 1);
	// name[name_len] = '\0';
	strcpy(*name, tmp1);
	if (tmp_name)
		strcat(*name, tmp_name);

//	if (need_to_free)
//		free(tmp_name);
}

// eLF_MEMBER

void get_member_name_len(void *type, int *res)
{
	STypeInfo *t = (STypeInfo *) type;
	SLF_MEMBER *lf = (SLF_MEMBER *)t->type_info;

	get_sval_name_len(&lf->offset, res);
}

void get_member_name(void *type, char **name)
{
	STypeInfo *t = (STypeInfo *) type;
	SLF_MEMBER *lf = (SLF_MEMBER *)t->type_info;

	get_sval_name(&lf->offset, name);
}

void get_member_val(void *type, int *res)
{
	STypeInfo *t = (STypeInfo *) type;
	SLF_MEMBER *lf = (SLF_MEMBER *)t->type_info;

	get_sval_val(&lf->offset, res);
}
 
int get_member_index(void *type, void **ret_type)
{
	STypeInfo *t = (STypeInfo *) type;
	SLF_MEMBER *lf = (SLF_MEMBER *) t->type_info;
	int curr_idx = lf->inedex;

	if (curr_idx < base_idx) {
		*ret_type = 0;
	} else {
		curr_idx -= base_idx;
		//*ret_type = r_list_get_n(p_types_list, curr_idx);
                *ret_type = (SType *)utarray_eltptr(p_types_list, curr_idx);
	}

	return curr_idx;
}

void free_lf_member(void *type_info)
{
	STypeInfo *typeInfo = (STypeInfo *) type_info;
	SLF_MEMBER *lf_mem = (SLF_MEMBER *) typeInfo->type_info;

	free_sval(&lf_mem->offset);
}

void get_member_print_type(void *type, char **name, int* pcount)
{
	STypeInfo *ti = (STypeInfo *) type;
	SType *t = 0;
	char *tmp_name = 0;
	int name_len = 0;
	int need_to_free = 1;
	int base_type = 0;

	base_type = ti->get_index(ti, (void **) &t);
	if (!t) {
		need_to_free = 0;
		print_base_type(base_type, &tmp_name);
	} else {
		ti = &t->type_data;
		ti->get_print_type(ti, &tmp_name, pcount);
	}

	//name_len = strlen("(member) ");
	if (tmp_name)
		name_len += strlen(tmp_name);
	*name = (char *) malloc(name_len + 1);
	// name[name_len] = '\0';
	//strcpy(*name, "(member) ");
	if (tmp_name)
		strcpy(*name, tmp_name);

	if (need_to_free) {
		free(tmp_name);
	}
}

// eLF_ONEMETHOD

void get_onemethod_name_len(void *type, int *res_len)
{
	STypeInfo *t = (STypeInfo *) type;
	SLF_ONEMETHOD *lf_onemethod = (SLF_ONEMETHOD *)t->type_info;

	*res_len = lf_onemethod->val.str_data.size;
}

void get_onemethod_name(void *type, char **name)
{
	STypeInfo *t = (STypeInfo *) type;
	SLF_ONEMETHOD *lf = (SLF_ONEMETHOD *)t->type_info;

	*name = lf->val.str_data.name;
}

void get_onemethod_val(void *type, int *res)
{
	STypeInfo *t = (STypeInfo *) type;
	SLF_ONEMETHOD *lf = (SLF_ONEMETHOD *) t->type_info;

	*res = lf->val.val;
}

int get_onemethod_index(void *type, void **ret_type)
{
	STypeInfo *t = (STypeInfo *) type;
	SLF_ONEMETHOD *lf = (SLF_ONEMETHOD *) t->type_info;
	int curr_idx = lf->index;

	if (curr_idx < base_idx) {
		*ret_type = 0;
	} else {
		curr_idx -= base_idx;
		//*ret_type = r_list_get_n(p_types_list, curr_idx);
                *ret_type = (SType *)utarray_eltptr(p_types_list, curr_idx);
	}

	return curr_idx;
}

void free_lf_onemethod(void *type)
{
	STypeInfo *t = (STypeInfo *) type;
	SLF_ONEMETHOD *lf_onemethod = (SLF_ONEMETHOD *) t->type_info;

	free(lf_onemethod->val.str_data.name);
}

void get_onemethod_print_type(void *type, char **name, int* pcount)
{
	STypeInfo *ti = (STypeInfo *) type;
	SType *t = 0;
	char *tmp_name = 0;
	int name_len = 0;
	int need_to_free = 1;
	int base_type = 0;

	base_type = ti->get_index(ti, (void **)&t);
	if (!t) {
		need_to_free = 0;
		print_base_type(base_type, &tmp_name);
	} else {
		ti = &t->type_data;
		ti->get_print_type(ti, &tmp_name, pcount);
	}

	name_len = strlen("onemethod ");
	if (tmp_name)
		name_len += strlen(tmp_name);
	*name = (char *) malloc(name_len + 1);
	// name[name_len] = '\0';
	strcpy(*name, "onemethod ");
	if (tmp_name)
		strcat(*name, tmp_name);

	if (need_to_free)
		free(tmp_name);
}


//=========================================================

void init_stype_info(STypeInfo *type_info)
{
	type_info->free_ = 0;
	type_info->get_members = 0;
	type_info->get_name = 0;
	type_info->get_val = 0;
	type_info->get_name_len = 0;
	type_info->get_arg_type = 0;
	type_info->get_element_type = 0;
	type_info->get_index_type = 0;
	type_info->get_base_type = 0;
	type_info->get_derived = 0;
	type_info->get_vshape = 0;
	type_info->get_utype = 0;
	type_info->get_return_type = 0;
	type_info->get_class_type = 0;
	type_info->get_this_type = 0;
	type_info->get_arglist = 0;
	type_info->get_index = 0;
	type_info->get_mlist = 0;
	type_info->get_modified_type = 0;
	type_info->is_fwdref = 0;
	type_info->get_print_type = 0;

        //printf("eLF type: %d\n", type_info->leaf_type);

	switch (type_info->leaf_type) {
	case eLF_FIELDLIST:
		type_info->get_members = get_fieldlist_members;
		type_info->free_ = free_lf_fieldlist;
		type_info->get_print_type = get_fieldlist_print_type;
		break;
        
	case eLF_ENUM:
		type_info->get_name = get_enum_name;
		type_info->get_name_len = get_enum_name_len;
		type_info->get_members = get_enum_members;
		type_info->get_utype = get_enum_utype;
		type_info->free_ = free_lf_enum;
		type_info->get_print_type = get_enum_print_type;
		break;
        
	case eLF_CLASS:
	case eLF_STRUCTURE:
		type_info->get_name = get_class_struct_name;
		type_info->get_val = get_class_struct_val; // for structure this is size
		type_info->get_name_len = get_class_struct_name_len;
		type_info->get_members = get_struct_class_members;
		type_info->get_derived = get_class_struct_derived;
		type_info->get_vshape = get_class_struct_vshape;
		type_info->is_fwdref = is_struct_class_fwdref;
		type_info->free_ = free_lf_class;
		type_info->get_print_type = get_class_struct_print_type;
		break;
        
	case eLF_POINTER:
		type_info->get_utype = get_pointer_utype;
		type_info->get_print_type = get_pointer_print_type;
		break;
        
	case eLF_ARRAY:
		type_info->get_name = get_array_name;
		type_info->get_val = get_array_val;
		type_info->get_name_len = get_array_name_len;
		type_info->get_element_type = get_array_element_type;
		type_info->get_index_type = get_array_index_type;
		type_info->free_ = free_lf_array;
		type_info->get_print_type = get_array_print_type;
		break;
	case eLF_MODIFIER:
		type_info->get_modified_type = get_modifier_modified_type;
		type_info->get_print_type = get_modifier_print_type;
		break;
	case eLF_ARGLIST:
		type_info->free_ = free_lf_arglist;
		type_info->get_print_type = get_arglist_print_type;
		break;
	case eLF_MFUNCTION:
		type_info->get_return_type = get_mfunction_return_type;
		type_info->get_class_type = get_mfunction_class_type;
		type_info->get_this_type = get_mfunction_this_type;
		type_info->get_arglist = get_mfunction_arglist;
		type_info->get_print_type = get_mfunction_print_type;
		break;
        
	case eLF_METHODLIST:
		break;
	case eLF_PROCEDURE:
		type_info->get_return_type = get_procedure_return_type;
		type_info->get_arglist = get_procedure_arglist;
		type_info->get_print_type = get_procedure_print_type;
		break;
        
	case eLF_UNION:
		type_info->get_name = get_union_name;
		type_info->get_val = get_union_val;
		type_info->get_name_len = get_union_name_len;
		type_info->get_members = get_union_members;
		type_info->is_fwdref = is_union_fwdref;
		type_info->free_ = free_lf_union;
		type_info->get_print_type = get_union_print_type;
		break;
	case eLF_BITFIELD:
		type_info->get_base_type = get_bitfield_base_type;
		type_info->get_print_type = get_bitfield_print_type;
		break;
        
	case eLF_VTSHAPE:
		type_info->free_ = free_lf_vtshape;
		type_info->get_print_type = get_vtshape_print_type;
		break;
	case eLF_ENUMERATE:
		type_info->get_name = get_enumerate_name;
		type_info->get_val = get_enumerate_val;
		type_info->get_name_len = get_enumerate_name_len;
		type_info->free_ = free_lf_enumerate;
		type_info->get_print_type = get_enumerate_print_type;
		break;
        
	case eLF_NESTTYPE:
		type_info->get_name = get_nesttype_name;
		type_info->get_name_len = get_nesttype_name_len;
		type_info->get_index = get_nesttype_index;
		type_info->free_ = free_lf_nesttype;
		type_info->get_print_type = get_nesttype_print_type;
		break;
	case eLF_METHOD:
		type_info->get_name = get_method_name;
		type_info->get_name_len = get_method_name_len;
		type_info->get_mlist = get_method_mlist;
		type_info->free_ = free_lf_method;
		type_info->get_print_type = get_method_print_type;
		break;
         
	case eLF_MEMBER:
		type_info->get_name = get_member_name;
		type_info->get_val = get_member_val;
		type_info->get_name_len = get_member_name_len;
		type_info->get_index = get_member_index;
		type_info->free_ = free_lf_member;
		type_info->get_print_type = get_member_print_type;
		break;
	case eLF_ONEMETHOD:
		type_info->get_name = get_onemethod_name;
		type_info->get_name_len = get_onemethod_name_len;
		type_info->get_val = get_onemethod_val;
		type_info->get_index = get_onemethod_index;
		type_info->free_ = free_lf_onemethod;
		type_info->get_print_type = get_onemethod_print_type;
		break;
        
	default:
		//printf("init_stype_info(): unknown type for init\n");
		type_info->get_name = 0;
		type_info->get_val = 0;
		type_info->get_name_len = 0;
		type_info->get_members = 0;
		type_info->get_arg_type = 0;
		type_info->get_element_type = 0;
		type_info->get_index_type = 0;
		type_info->get_base_type = 0;
		type_info->get_derived = 0;
		type_info->get_vshape = 0;
		type_info->get_utype = 0;
		type_info->get_return_type = 0;
		type_info->get_class_type = 0;
		type_info->get_this_type = 0;
		type_info->get_arglist = 0;
		type_info->get_index = 0;
		type_info->get_mlist = 0;
		type_info->get_print_type = 0;
		break;
	}
}

void dumpTPIHeader(STPIHeader* header)
{
    printf("=============================\n");
    printf("version: %d\n", header->version);
    printf("hdr_size: %d\n", header->hdr_size);
    printf("ti_min: %d\n", header->ti_min);
    printf("ti_max: %d\n", header->ti_max);
    printf("follow_size: %d\n", header->follow_size);
    printf("=============================\n");
}

//=================================================================
// parse_lf

/*
#define PARSE_LF2(lf_type, lf_func_name, type) { \
        STypeInfo *type_info = (STypeInfo *) malloc(sizeof(STypeInfo)); \
        lf_type *lf = (lf_type *) malloc(sizeof(lf_type)); \
        curr_read_bytes = parse_##lf_func_name(lf, p, read_bytes, len); \
        type_info->type_info = (void *) lf; \
        type_info->leaf_type = type; \
        init_stype_info(type_info); \
        r_list_append(lf_fieldlist->substructs, type_info); \
}


*/

void init_scstring(SCString *cstr, unsigned int size, char *name)
{
	cstr->size = size;
	cstr->name = (char *) malloc(size);
	strcpy(cstr->name, name);
}

int parse_sctring(SCString *sctr, unsigned char *leaf_data, unsigned int *read_bytes, unsigned int len)
{
	unsigned int c = 0;

	sctr->name = 0;

	while (*leaf_data != 0) {
		CAN_READ((*read_bytes + c), 1, len);
		c++;
		leaf_data++;
	}
	CAN_READ(*read_bytes, 1, len);
	leaf_data += 1;
	(*read_bytes) += (c + 1);

	init_scstring(sctr, c + 1, (char *)leaf_data - (c + 1));
	return 1;
}

int parse_sval(SVal *val, unsigned char *leaf_data, unsigned int *read_bytes, unsigned int len)
{
	val->name_or_val = 0;

	READ(*read_bytes, 2, len, val->value_or_type, leaf_data, unsigned short);

	if (val->value_or_type < eLF_CHAR) {
		SCString *sctr = (SCString *) malloc(sizeof(SCString));
		parse_sctring(sctr, leaf_data, read_bytes, len);
		val->name_or_val = sctr;
	} else {
		switch (val->value_or_type) {
		case eLF_CHAR:
		{
			SVal_LF_CHAR lf_char;
			READ(*read_bytes, 2, len, lf_char.value, leaf_data, char);
			parse_sctring(&lf_char.name, leaf_data, read_bytes, len);
			val->name_or_val = malloc(sizeof(SVal_LF_CHAR));
			memcpy(val->name_or_val, &lf_char, sizeof(SVal_LF_CHAR));
			break;

		}
		case eLF_LONG:
		{
			SVal_LF_LONG lf_long;
			lf_long.value = 0;
			// long = 4 bytes for Windows, but not in Linux x64,
			// so here is using int instead of long when
			// reading long value
			READ(*read_bytes, 4, len, lf_long.value, leaf_data, int);
			parse_sctring(&lf_long.name, leaf_data, read_bytes, len);
			val->name_or_val = malloc(sizeof(SVal_LF_LONG));
			memcpy(val->name_or_val, &lf_long, sizeof(SVal_LF_LONG));
			break;
		}
		case eLF_ULONG:
		{
			SVal_LF_ULONG lf_ulong;
			lf_ulong.value = 0;
			// unsinged long = 4 bytes for Windows, but not in Linux x64,
			// so here is using unsinged int instead of unsigned long when
			// reading ulong value
			READ(*read_bytes, 4, len, lf_ulong.value, leaf_data, unsigned int);
			parse_sctring(&lf_ulong.name, leaf_data, read_bytes, len);
			val->name_or_val = malloc(sizeof(SVal_LF_ULONG));
			memcpy(val->name_or_val, &lf_ulong, sizeof(SVal_LF_ULONG));
			break;
		}
		case eLF_SHORT:
		{
			SVal_LF_SHORT lf_short;
			READ(*read_bytes, 2, len, lf_short.value, leaf_data, short);
			parse_sctring(&lf_short.name, leaf_data, read_bytes, len);
			val->name_or_val = malloc(sizeof(SVal_LF_SHORT));
			memcpy(val->name_or_val, &lf_short, sizeof(SVal_LF_SHORT));
			break;
		}
		case eLF_USHORT:
		{
			SVal_LF_USHORT lf_ushort;
			READ(*read_bytes, 2, len, lf_ushort.value, leaf_data, unsigned short);
			parse_sctring(&lf_ushort.name, leaf_data, read_bytes, len);
			val->name_or_val = malloc(sizeof(SVal_LF_USHORT));
			memcpy(val->name_or_val, &lf_ushort, sizeof(SVal_LF_USHORT));
			break;
		}
		default:
			printf("parse_sval()::oops\n");
			return 0;
		}
	}

	return 1;
}

#define PARSE_LF2(lf_type, lf_func_name, type) { \
	STypeInfo *type_info = (STypeInfo *) malloc(sizeof(STypeInfo)); \
	lf_type *lf = (lf_type *) malloc(sizeof(lf_type)); \
	curr_read_bytes = parse_##lf_func_name(lf, p, read_bytes, len); \
	type_info->type_info = (void *) lf; \
	type_info->leaf_type = type; \
	init_stype_info(type_info); \
        utarray_push_back(lf_fieldlist->substructs, type_info);\
}

UT_icd STypeInfo_icd = {sizeof(STypeInfo), NULL, NULL, NULL};

int parse_lf_fieldlist(SLF_FIELDLIST *lf_fieldlist,  unsigned char *leaf_data, unsigned int *read_bytes, unsigned int len)
{
	ELeafType leaf_type;
	int curr_read_bytes = 0;
	unsigned char *p = leaf_data;

	//lf_fieldlist->substructs = r_list_new();
        utarray_new(lf_fieldlist->substructs, &STypeInfo_icd);

	while (*read_bytes <= len) {
		READ(*read_bytes, 2, len, leaf_type, p, unsigned short);
		switch (leaf_type) {
		case eLF_ENUMERATE:
			PARSE_LF2(SLF_ENUMERATE, lf_enumerate, eLF_ENUMERATE);
			break;
		case eLF_NESTTYPE:
			PARSE_LF2(SLF_NESTTYPE, lf_nesttype, eLF_NESTTYPE);
			break;
		case eLF_METHOD:
			PARSE_LF2(SLF_METHOD, lf_method, eLF_METHOD);
			break;
		case eLF_MEMBER:
			PARSE_LF2(SLF_MEMBER, lf_member, eLF_MEMBER);
			break;
		case eLF_ONEMETHOD:
			PARSE_LF2(SLF_ONEMETHOD, lf_onemethod, eLF_ONEMETHOD);
			break;
		default:
//			printf("unsupported leaf type in parse_lf_fieldlist()\n");
			return 0;
		}

		if (curr_read_bytes != 0) {
			p += curr_read_bytes;
		} else return 0;
	}
	return 0;
}

int parse_lf_enumerate(SLF_ENUMERATE *lf_enumerate, unsigned char *leaf_data, unsigned int *read_bytes, unsigned int len)
{
	unsigned int read_bytes_before = 0, tmp_read_bytes_before = 0;

	lf_enumerate->enum_value.name_or_val = 0;

	read_bytes_before = *read_bytes;
	READ(*read_bytes, 2, len, lf_enumerate->fldattr.fldattr, leaf_data, unsigned short);

	tmp_read_bytes_before = *read_bytes;
	parse_sval(&lf_enumerate->enum_value, leaf_data, read_bytes, len);
	leaf_data += (*read_bytes - tmp_read_bytes_before);

	PEEK_READ(*read_bytes, 1, len, lf_enumerate->pad, leaf_data, unsigned char);
	PAD_ALIGN(lf_enumerate->pad, *read_bytes, leaf_data, len);

	//printf("%s:", "parse_lf_enumerate()");
	//printf_sval_name(&lf_enumerate->enum_value);
	//printf("\n");

	return (*read_bytes - read_bytes_before);
}

int parse_lf_nesttype(SLF_NESTTYPE *lf_nesttype, unsigned char *leaf_data, unsigned int *read_bytes, unsigned int len)
{
	unsigned int read_bytes_before = *read_bytes;

	lf_nesttype->name.name = 0;

	READ(*read_bytes, 2, len, lf_nesttype->pad, leaf_data, unsigned short);
	READ(*read_bytes, 4, len, lf_nesttype->index, leaf_data, unsigned short);

	parse_sctring(&lf_nesttype->name, leaf_data, read_bytes, len);
//	printf("parse_lf_nesttype(): name = %s\n", lf_nesttype->name.name);

	return *read_bytes - read_bytes_before;
}

int parse_lf_method(SLF_METHOD *lf_method, unsigned char *leaf_data, unsigned int *read_bytes, unsigned int len)
{
	unsigned int read_bytes_before = *read_bytes, tmp_read_bytes_before = 0;

	lf_method->name.name = 0;

	READ(*read_bytes, 2, len, lf_method->count, leaf_data, unsigned short);
	READ(*read_bytes, 4, len, lf_method->mlist, leaf_data, unsigned int);

	tmp_read_bytes_before = *read_bytes;
	parse_sctring(&lf_method->name, leaf_data, read_bytes, len);
	leaf_data += (*read_bytes - tmp_read_bytes_before);

	PEEK_READ(*read_bytes, 1, len, lf_method->pad, leaf_data, unsigned char);
	PAD_ALIGN(lf_method->pad, *read_bytes, leaf_data, len);

//	printf("parse_lf_method(): name = %s\n", lf_method->name.name);

	return *read_bytes - read_bytes_before;
}

int parse_lf_member(SLF_MEMBER *lf_member, unsigned char *leaf_data, unsigned int *read_bytes, unsigned int len)
{
	int read_bytes_before = *read_bytes, tmp_read_bytes_before = 0;

	lf_member->offset.name_or_val = 0;

	READ(*read_bytes, 2, len, lf_member->fldattr.fldattr, leaf_data, unsigned short);
	READ(*read_bytes, 4, len, lf_member->inedex, leaf_data, unsigned int);

	tmp_read_bytes_before = *read_bytes;
	parse_sval(&lf_member->offset, leaf_data, read_bytes, len);
	leaf_data += (*read_bytes - tmp_read_bytes_before);

	PEEK_READ(*read_bytes, 1, len, lf_member->pad, leaf_data, unsigned char);
	PAD_ALIGN(lf_member->pad, *read_bytes, leaf_data, len);

//	printf("parse_lf_member(): name = ");
//	printf_sval_name(&lf_member->offset);
//	printf("\n");

	return (*read_bytes - read_bytes_before);
}

int parse_lf_onemethod(SLF_ONEMETHOD *lf_onemethod, unsigned char *leaf_data, unsigned int *read_bytes, unsigned int len)
{
	int read_bytes_before = *read_bytes, tmp_before_read_bytes = 0;

	lf_onemethod->val.str_data.name = 0;
	lf_onemethod->val.val = 0;

	READ(*read_bytes, 2, len, lf_onemethod->fldattr.fldattr, leaf_data, unsigned short);
	READ(*read_bytes, 4, len, lf_onemethod->index, leaf_data, unsigned int);

	lf_onemethod->fldattr.fldattr = SWAP_UINT16(lf_onemethod->fldattr.fldattr);

	if((lf_onemethod->fldattr.bits.mprop == eMTintro) ||
		(lf_onemethod->fldattr.bits.mprop == eMTpureintro)) {
		READ(*read_bytes, 4, len, lf_onemethod->val.val, leaf_data, unsigned int);
	}

	tmp_before_read_bytes = *read_bytes;
	parse_sctring(&(lf_onemethod->val.str_data), leaf_data, read_bytes, len);
	leaf_data += (*read_bytes - tmp_before_read_bytes);

	PEEK_READ(*read_bytes, 1, len, lf_onemethod->pad, leaf_data, unsigned char);
	PAD_ALIGN(lf_onemethod->pad, *read_bytes, leaf_data, len);

	return (*read_bytes - read_bytes_before);
}

int parse_lf_enum(SLF_ENUM *lf_enum, unsigned char *leaf_data, unsigned int *read_bytes, unsigned int len)
{
	unsigned int tmp_before_read_bytes = *read_bytes;
	unsigned int before_read_bytes = 0;

	lf_enum->name.name = 0;

	READ(*read_bytes, 2, len, lf_enum->count, leaf_data, unsigned short);
	READ(*read_bytes, 2, len, lf_enum->prop.cv_property, leaf_data, unsigned short);
	READ(*read_bytes, 4, len, lf_enum->utype, leaf_data, unsigned int);
	READ(*read_bytes, 4, len, lf_enum->field_list, leaf_data, unsigned int);

	lf_enum->prop.cv_property = SWAP_UINT16(lf_enum->prop.cv_property);
	before_read_bytes = *read_bytes;
	parse_sctring(&lf_enum->name, leaf_data, read_bytes, len);
	leaf_data += (*read_bytes - before_read_bytes);

	PEEK_READ(*read_bytes, 1, len, lf_enum->pad, leaf_data, unsigned char);
	PAD_ALIGN(lf_enum->pad, *read_bytes, leaf_data, len);

//	printf("parse_lf_enum(): name = %s\n", lf_enum->name.name);
	return *read_bytes - tmp_before_read_bytes;
}

int parse_lf_class(SLF_CLASS *lf_class, unsigned char *leaf_data, unsigned int *read_bytes, unsigned int len)
{
//	SLF_CLASS lf_class;
	unsigned int tmp_before_read_bytes = *read_bytes;
	unsigned int before_read_bytes = 0;

	lf_class->size.name_or_val = 0;

	READ(*read_bytes, 2, len, lf_class->count, leaf_data, unsigned short);
	READ(*read_bytes, 2, len, lf_class->prop.cv_property, leaf_data, unsigned short);
	READ(*read_bytes, 4, len, lf_class->field_list, leaf_data, unsigned int);
	READ(*read_bytes, 4, len, lf_class->derived, leaf_data, unsigned int);
	READ(*read_bytes, 4, len, lf_class->vshape, leaf_data, unsigned int);

	before_read_bytes = *read_bytes;
	parse_sval(&lf_class->size, leaf_data, read_bytes, len);
	before_read_bytes = *read_bytes - before_read_bytes;
	leaf_data = (unsigned char *)leaf_data + before_read_bytes;

	PEEK_READ(*read_bytes, 1, len, lf_class->pad, leaf_data, unsigned char);
	PAD_ALIGN(lf_class->pad, *read_bytes, leaf_data, len);

//	printf("%s:", "parse_lf_class()");
//	printf_sval_name(&lf_class->size);
//	printf("\n");
	return *read_bytes - tmp_before_read_bytes;
}

int parse_lf_structure(SLF_STRUCTURE *lf_structure, unsigned char *leaf_data, unsigned int *read_bytes, unsigned int len)
{
//	SLF_STRUCTURE lf_structure;
	unsigned int tmp_before_read_bytes = *read_bytes;
	unsigned int before_read_bytes = 0;

	lf_structure->size.name_or_val = 0;

	READ(*read_bytes, 2, len, lf_structure->count, leaf_data, unsigned short);
	READ(*read_bytes, 2, len, lf_structure->prop.cv_property, leaf_data, unsigned short);
	READ(*read_bytes, 4, len, lf_structure->field_list, leaf_data, unsigned int);
	READ(*read_bytes, 4, len, lf_structure->derived, leaf_data, unsigned int);
	READ(*read_bytes, 4, len, lf_structure->vshape, leaf_data, unsigned int);

	lf_structure->prop.cv_property = SWAP_UINT16(lf_structure->prop.cv_property);

	before_read_bytes = *read_bytes;
	parse_sval(&lf_structure->size, leaf_data, read_bytes, len);
	leaf_data += (*read_bytes - before_read_bytes);

	PEEK_READ(*read_bytes, 1, len, lf_structure->pad, leaf_data, unsigned char);
	PAD_ALIGN(lf_structure->pad, *read_bytes, leaf_data, len);

//	printf("parse_lf_structure(): name = ");
//	printf_sval_name(&lf_structure->size);
//	printf("\n");
	return *read_bytes - tmp_before_read_bytes;
}

int parse_lf_pointer(SLF_POINTER *lf_pointer, unsigned char *leaf_data, unsigned int *read_bytes, unsigned int len)
{
	unsigned int tmp_before_read_bytes = *read_bytes;

	READ(*read_bytes, 4, len, lf_pointer->utype, leaf_data, unsigned int);
	READ(*read_bytes, 4, len, lf_pointer->ptr_attr.ptr_attr, leaf_data, unsigned int);

	lf_pointer->ptr_attr.ptr_attr = SWAP_UINT32(lf_pointer->ptr_attr.ptr_attr);

	PEEK_READ(*read_bytes, 1, len, lf_pointer->pad, leaf_data, unsigned char);
	PAD_ALIGN(lf_pointer->pad, *read_bytes, leaf_data, len);

	return *read_bytes - tmp_before_read_bytes;
}

int parse_lf_array(SLF_ARRAY *lf_array, unsigned char *leaf_data, unsigned int *read_bytes, unsigned int len)
{
	unsigned int tmp_before_read_bytes = *read_bytes;
	unsigned int before_read_bytes = 0;

	lf_array->size.name_or_val = 0;

	READ(*read_bytes, 4, len, lf_array->element_type, leaf_data, unsigned int);
	READ(*read_bytes, 4, len, lf_array->index_type, leaf_data, unsigned int);

	before_read_bytes = *read_bytes;
	parse_sval(&lf_array->size, leaf_data, read_bytes, len);
	leaf_data += (*read_bytes - before_read_bytes);

	PEEK_READ(*read_bytes, 1, len, lf_array->pad, leaf_data, unsigned char);
	PAD_ALIGN(lf_array->pad, *read_bytes, leaf_data, len);

//	printf("parse_lf_array(): name = ");
//	printf_sval_name(&lf_array->size);
//	printf("\n");
	return *read_bytes - tmp_before_read_bytes;
}

int parse_lf_modifier(SLF_MODIFIER *lf_modifier, unsigned char *leaf_data, unsigned int *read_bytes, unsigned int len)
{
	unsigned int tmp_before_read_bytes = *read_bytes;

	READ(*read_bytes, 4, len, lf_modifier->modified_type, leaf_data, unsigned int);
	READ(*read_bytes, 2, len, lf_modifier->umodifier.modifier, leaf_data, unsigned short);
	lf_modifier->umodifier.modifier = SWAP_UINT16(lf_modifier->umodifier.modifier);

	PEEK_READ(*read_bytes, 1, len, lf_modifier->pad, leaf_data, unsigned char);
	PAD_ALIGN(lf_modifier->pad, *read_bytes, leaf_data, len);

	return *read_bytes - tmp_before_read_bytes;
}

int parse_lf_arglist(SLF_ARGLIST *lf_arglist, unsigned char *leaf_data, unsigned int *read_bytes, unsigned int len)
{
	unsigned int tmp_before_read_bytes = *read_bytes;

	lf_arglist->arg_type = 0;

	READ(*read_bytes, 4, len, lf_arglist->count, leaf_data, unsigned int);

	lf_arglist->arg_type = (unsigned int *) malloc(lf_arglist->count * 4);
	memcpy(lf_arglist->arg_type, leaf_data, lf_arglist->count * 4);
	leaf_data += (lf_arglist->count * 4);
	*read_bytes += (lf_arglist->count * 4);

	PEEK_READ(*read_bytes, 1, len, lf_arglist->pad, leaf_data, unsigned char);
	PAD_ALIGN(lf_arglist->pad, *read_bytes, leaf_data, len);

	return *read_bytes - tmp_before_read_bytes;
}

int parse_lf_mfunction(SLF_MFUNCTION *lf_mfunction, unsigned char *leaf_data, unsigned int *read_bytes, unsigned int len)
{
	unsigned int tmp_before_read_bytes = *read_bytes;

	READ(*read_bytes, 4, len, lf_mfunction->return_type, leaf_data, unsigned int);
	READ(*read_bytes, 4, len, lf_mfunction->class_type, leaf_data, unsigned int);
	READ(*read_bytes, 4, len, lf_mfunction->this_type, leaf_data, unsigned int);
	READ(*read_bytes, 1, len, lf_mfunction->call_conv, leaf_data, unsigned char);
	READ(*read_bytes, 1, len, lf_mfunction->reserved, leaf_data, unsigned char);
	READ(*read_bytes, 2, len, lf_mfunction->parm_count, leaf_data, unsigned short);
	READ(*read_bytes, 4, len, lf_mfunction->arglist, leaf_data, unsigned int);
	READ(*read_bytes, 4, len, lf_mfunction->this_adjust, leaf_data, int);

	PEEK_READ(*read_bytes, 1, len, lf_mfunction->pad, leaf_data, unsigned char);
	PAD_ALIGN(lf_mfunction->pad, *read_bytes, leaf_data, len);

	return *read_bytes - tmp_before_read_bytes;
}

int parse_lf_procedure(SLF_PROCEDURE *lf_procedure, unsigned char *leaf_data, unsigned int *read_bytes, unsigned int len)
{
	unsigned int tmp_before_read_bytes = *read_bytes;

	READ(*read_bytes, 4, len, lf_procedure->return_type, leaf_data, unsigned int);
	READ(*read_bytes, 1, len, lf_procedure->call_conv, leaf_data, unsigned char);
	READ(*read_bytes, 1, len, lf_procedure->reserved, leaf_data, unsigned char);
	READ(*read_bytes, 2, len, lf_procedure->parm_count, leaf_data, unsigned short);
	READ(*read_bytes, 4, len, lf_procedure->arg_list, leaf_data, unsigned int);

	PEEK_READ(*read_bytes, 1, len, lf_procedure->pad, leaf_data, unsigned char);
	PAD_ALIGN(lf_procedure->pad, *read_bytes, leaf_data, len);

	return *read_bytes - tmp_before_read_bytes;
}

int parse_lf_union(SLF_UNION *lf_union, unsigned char *leaf_data, unsigned int *read_bytes, unsigned int len)
{
	unsigned int tmp_before_read_bytes = *read_bytes;
	unsigned int before_read_bytes = 0;

	lf_union->size.name_or_val = 0;

	READ(*read_bytes, 2, len, lf_union->count, leaf_data, unsigned short);
	READ(*read_bytes, 2, len, lf_union->prop.cv_property, leaf_data, unsigned short);
	READ(*read_bytes, 4, len, lf_union->field_list, leaf_data, unsigned int);

	before_read_bytes = *read_bytes;
	parse_sval(&lf_union->size, leaf_data, read_bytes, len);
	before_read_bytes = *read_bytes - before_read_bytes;
	leaf_data = (unsigned char *)leaf_data + before_read_bytes;

	PEEK_READ(*read_bytes, 1, len, lf_union->pad, leaf_data, unsigned char);
	PAD_ALIGN(lf_union->pad, *read_bytes, leaf_data, len);

//	printf("%s:", "parse_lf_union()");
//	printf_sval_name(&lf_union->size);
//	printf("\n");
	return *read_bytes - tmp_before_read_bytes;
}

int parse_lf_bitfield(SLF_BITFIELD *lf_bitfield, unsigned char *leaf_data, unsigned int *read_bytes, unsigned int len)
{
	unsigned int tmp_before_read_bytes = *read_bytes;

	READ(*read_bytes, 4, len, lf_bitfield->base_type, leaf_data, unsigned int);
	READ(*read_bytes, 1, len, lf_bitfield->length, leaf_data, unsigned char);
	READ(*read_bytes, 1, len, lf_bitfield->position, leaf_data, unsigned char);

	PEEK_READ(*read_bytes, 1, len, lf_bitfield->pad, leaf_data, unsigned char);
	PAD_ALIGN(lf_bitfield->pad, *read_bytes, leaf_data, len);

	return *read_bytes - tmp_before_read_bytes;
}

int parse_lf_vtshape(SLF_VTSHAPE *lf_vtshape, unsigned char *leaf_data, unsigned int *read_bytes, unsigned int len)
{
	unsigned int tmp_before_read_bytes = *read_bytes;
	unsigned int size; // in bytes;

	lf_vtshape->vt_descriptors = 0;

	READ(*read_bytes, 2, len, lf_vtshape->count, leaf_data, unsigned short);

	size = (4 * lf_vtshape->count + (lf_vtshape->count % 2) * 4) / 8;
	lf_vtshape->vt_descriptors = (char *) malloc(size);
	memcpy(lf_vtshape->vt_descriptors, leaf_data, size);
	leaf_data += size;
	*read_bytes += size;

	PEEK_READ(*read_bytes, 1, len, lf_vtshape->pad, leaf_data, unsigned char);
	PAD_ALIGN(lf_vtshape->pad, *read_bytes, leaf_data, len);

	return *read_bytes - tmp_before_read_bytes;
}

#define PARSE_LF(lf_type, lf_func) { \
	lf_type *lf = (lf_type *) malloc(sizeof(lf_type)); \
	parse_##lf_func(lf, leaf_data + 2, &read_bytes, type->length); \
	type->type_data.type_info = (void *) lf; \
	init_stype_info(&type->type_data); \
}

int parse_tpi_stypes(R_STREAM_FILE *stream, SType *type) {
	unsigned char *leaf_data;
	unsigned int read_bytes = 0;

	stream_file_read(stream, 2, (char *)&type->length);
	if (type->length<1)
		return 0;
	leaf_data = (unsigned char *) malloc(type->length);
	stream_file_read (stream, type->length, (char *)leaf_data);
	type->type_data.leaf_type = *(unsigned short *)leaf_data;
	read_bytes += 2;
	switch (type->type_data.leaf_type) {
	case eLF_FIELDLIST:
//		printf("eLF_FIELDLIST\n");
		PARSE_LF(SLF_FIELDLIST, lf_fieldlist);
		break;
	case eLF_ENUM:
//		printf("eLF_ENUM\n");
		PARSE_LF(SLF_ENUM, lf_enum);
		break;
	// TODO: combine with eLF_STRUCTURE
	case eLF_CLASS:
//		printf("eLF_CLASS\n");
		PARSE_LF(SLF_CLASS, lf_class);
		break;
	case eLF_STRUCTURE:
//		printf("eLF_STRUCTURE\n");
		PARSE_LF(SLF_STRUCTURE, lf_structure);
		break;
	case eLF_POINTER:
//		printf("eLF_POINTER\n");
	{
		SLF_POINTER *lf = (SLF_POINTER *) malloc(sizeof(SLF_POINTER)); \
		parse_lf_pointer(lf, leaf_data + 2, &read_bytes, type->length); \
		type->type_data.type_info = (void *) lf; \
		init_stype_info(&type->type_data); \
	}
//		PARSE_LF(SLF_POINTER, lf_pointer);
		break;
	case eLF_ARRAY:
//		printf("eLF_ARRAY\n");
		PARSE_LF(SLF_ARRAY, lf_array);
		break;
	case eLF_MODIFIER:
//		printf("eLF_MODIFIER\n");
		PARSE_LF(SLF_MODIFIER, lf_modifier);
		break;
	case eLF_ARGLIST:
//		printf("eLF_ARGLIST\n");
		PARSE_LF(SLF_ARGLIST, lf_arglist);
		break;
	case eLF_MFUNCTION:
//		printf("eLF_MFUNCTION\n");
		PARSE_LF(SLF_MFUNCTION, lf_mfunction);
		break;
	case eLF_METHODLIST:
//		printf("eLF_METHOD_LIST\n");
		break;
	case eLF_PROCEDURE:
//		printf("eLF_PROCEDURE\n");
		PARSE_LF(SLF_PROCEDURE, lf_procedure);
		break;
	case eLF_UNION:
//		printf("eLF_UNION\n");
		PARSE_LF(SLF_UNION, lf_union);
		break;
	case eLF_BITFIELD:
//		printf("eLF_BITFIELD\n");
		PARSE_LF(SLF_BITFIELD, lf_bitfield);
		break;
	case eLF_VTSHAPE:
//		printf("eLF_VTSHAPE\n");
		PARSE_LF(SLF_VTSHAPE, lf_vtshape);
		break;
	default:
		printf("parse_tpi_streams(): unsupported leaf type\n");
		break;
	}

	free (leaf_data);
	return read_bytes;
}

UT_icd SType_icd = {sizeof(SType), NULL, NULL, NULL};

int parse_tpi_stream(void *parsed_pdb_stream, R_STREAM_FILE *stream) {
	int i;
	SType *type = 0;
	STpiStream *tpi_stream = (STpiStream *) parsed_pdb_stream;
	//tpi_stream->types = r_list_new();
        utarray_new( tpi_stream->types, &SType_icd);
	p_types_list = tpi_stream->types;

	stream_file_read(stream, sizeof(STPIHeader), (char *)&tpi_stream->header);

        dumpTPIHeader(&(tpi_stream->header));

	base_idx = tpi_stream->header.ti_min;

	for (i = tpi_stream->header.ti_min; i < tpi_stream->header.ti_max; i++) {
		type = (SType *) malloc(sizeof(SType));
		type->tpi_idx = i;
		type->type_data.type_info = 0;
		type->type_data.leaf_type = eLF_MAX;
		init_stype_info(&type->type_data);
		if (!parse_tpi_stypes(stream, type)) {
			free (type);
			return 0;
		}
		//r_list_append(tpi_stream->types, type);
                utarray_push_back(tpi_stream->types, type);
	}
	return 1;
	// Postprocessing...
}

void init_tpi_stream(STpiStream *tpi_stream)
{
	//tpi_stream->free_ = free_tpi_stream;
        return; 
}
